#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdbool.h>
#include <unistd.h>
#include <time.h>
#include <sys/mman.h>          // Linux内存锁定函数(mlock/munlock)依赖
#include <security/pam_appl.h> // PAM系统认证框架依赖
#include "raylib.h"            // Raylib图形库（窗口/渲染/输入）
#include "config.h"            // 模式配置文件（Debug/System切换）

// 对于旧标准，显式声明strdup
extern char *strdup(const char *s);

// ================================================================================
// 全局配置常量（系统级安全参数）
// ================================================================================
#define WINDOW_TITLE "System Screen Locker" // 窗口标题（系统显示用）
#define FONT_SIZE_MAIN 40                   // 主标题字体大小（建议30-60）
#define FONT_SIZE_SUB 30                    // 副标题/提示字体大小（建议20-50）
#define FONT_SIZE_INDICATOR 28              // 密码输入指示器字体大小（建议20-40）
#define COLOR_BACKGROUND BLACK              // 背景色（黑色防窥）
#define COLOR_TEXT WHITE                    // 普通文本色（白色高对比度）
#define COLOR_ERROR RED                     // 错误提示色（红色警示）
#define COLOR_SUCCESS GREEN                 // 成功状态色（绿色确认）
#define MAX_PASSWORD_LEN 512                // 密码最大长度（防缓冲区溢出）
#define MAX_FAILED_ATTEMPTS 5               // 最大失败次数（防暴力破解）

// ================================================================================
// 静态断言（修复：移到main函数内，兼容所有C标准；检查宏定义有效性）
// 作用：编译期验证关键参数范围，避免非法值导致运行异常
// ================================================================================
static void validate_config_macros()
{
    // 1. 主标题字体大小检查（30-60之间：太小看不清，太大超出屏幕）
    static_assert(FONT_SIZE_MAIN >= 30 && FONT_SIZE_MAIN <= 60,
                  "FONT_SIZE_MAIN must be between 30 and 60 (inclusive)");

    // 2. 副标题字体大小检查（20-50且小于主标题：层级清晰）
    static_assert(FONT_SIZE_SUB >= 20 && FONT_SIZE_SUB <= 50 && FONT_SIZE_SUB < FONT_SIZE_MAIN,
                  "FONT_SIZE_SUB must be 20-50 and smaller than FONT_SIZE_MAIN");

    // 3. 密码指示器字体大小检查（20-40且小于副标题：聚焦输入）
    static_assert(FONT_SIZE_INDICATOR >= 20 && FONT_SIZE_INDICATOR <= 40 && FONT_SIZE_INDICATOR < FONT_SIZE_SUB,
                  "FONT_SIZE_INDICATOR must be 20-40 and smaller than FONT_SIZE_SUB");

    // 4. 最大密码长度检查（128-1024：平衡安全性与内存占用）
    static_assert(MAX_PASSWORD_LEN >= 128 && MAX_PASSWORD_LEN <= 1024,
                  "MAX_PASSWORD_LEN must be between 128 and 1024 (inclusive)");

    // 5. 最大失败尝试次数检查（3-10：平衡用户体验与防暴力破解）
    static_assert(MAX_FAILED_ATTEMPTS >= 3 && MAX_FAILED_ATTEMPTS <= 10,
                  "MAX_FAILED_ATTEMPTS must be between 3 and 10 (inclusive)");
}

// ================================================================================
// 全局状态变量（记录锁屏运行时数据）
// ================================================================================
char password[MAX_PASSWORD_LEN] = {0}; // 密码缓冲区（存储用户输入）
int input_pos = 0;                     // 密码输入位置指针（跟踪输入长度）
int failed_attempts = 0;               // 认证失败次数计数器
bool is_locked = true;                 // 锁屏状态标记（true=锁定，false=解锁）
bool show_help = false;                // 帮助文本显示标记（F1切换）

// ================================================================================
// PAM认证回调函数（系统密码验证核心）
// 作用：将用户输入的密码传递给PAM框架，完成系统级身份验证
// ================================================================================
static int pam_conv_callback(int num_msg, const struct pam_message **msg,
                             struct pam_response **resp, void *appdata_ptr)
{
    (void)appdata_ptr; // 消除未使用参数警告
    // 为PAM响应分配内存（按消息数量申请）
    *resp = calloc(num_msg, sizeof(struct pam_response));
    if (!*resp)
        return PAM_BUF_ERR; // 内存分配失败，返回PAM缓冲区错误

    // 处理PAM消息（仅响应"隐藏输入"类型的密码请求）
    for (int i = 0; i < num_msg; i++)
    {
        if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF)
        {
            resp[i]->resp = strdup(password); // 复制用户输入的密码
            resp[i]->resp_retcode = 0;        // 响应状态：成功
        }
    }
    return PAM_SUCCESS; // 回调执行成功
}

// ================================================================================
// PAM密码验证函数（触发系统认证流程）
// 返回值：true=认证成功，false=认证失败
// ================================================================================
static bool verify_password()
{
    // 空密码直接拒绝（防止无密码解锁）
    if (input_pos == 0)
        return false;

    struct pam_conv conv = {pam_conv_callback, NULL};           // PAM回调结构体
    pam_handle_t *pam_handle = NULL;                            // PAM句柄（跟踪认证过程）
    const char *username = getlogin();                          // 获取当前登录用户名（与系统用户匹配）
    int ret = pam_start("login", username, &conv, &pam_handle); // 初始化PAM（使用login服务）

    // PAM初始化失败处理
    if (ret != PAM_SUCCESS)
    {
#if ENABLE_DEBUG_LOG
        fprintf(stderr, "PAM Init Fail: %s\n", pam_strerror(pam_handle, ret));
#endif
        pam_end(pam_handle, ret); // 释放PAM资源
        return false;
    }

    // 执行PAM认证（核心步骤：验证密码是否匹配系统用户）
    ret = pam_authenticate(pam_handle, 0);
    pam_end(pam_handle, ret); // 结束PAM会话，释放资源

    // 处理认证结果
    if (ret == PAM_SUCCESS)
    {
#if ENABLE_DEBUG_LOG
        printf("Auth Success!\n"); // 调试模式下打印成功日志
#endif
        return true;
    }
    else
    {
#if ENABLE_DEBUG_LOG
        fprintf(stderr, "Auth Fail: %s\n", pam_strerror(NULL, ret));
#endif
        failed_attempts++; // 认证失败，递增失败计数器
        return false;
    }
}

// ================================================================================
// 密码缓冲区安全清空函数
// 作用：用0覆盖密码数据，防止内存中残留明文密码（安全合规）
// ================================================================================
static void clear_password()
{
    memset(password, 0, sizeof(password)); // 内存清零（覆盖所有密码字符）
    input_pos = 0;                         // 重置输入指针
}

// ================================================================================
// 输入处理函数（键盘事件核心逻辑）
// 规则：系统模式下ESC仅清空输入，调试模式下ESC可退出（通过config.h控制）
// ================================================================================
static void handle_input()
{
    if (!is_locked)
        return; // 已解锁状态，忽略输入

    // F1键：切换帮助文本显示（系统/调试模式均支持）
    if (IsKeyPressed(KEY_F1))
    {
        show_help = !show_help;
    }

    // ESC键：根据模式执行不同操作（调试模式退出，系统模式清空）
    if (IsKeyPressed(KEY_ESCAPE))
    {
#if ALLOW_ESC_QUIT
        // 调试模式：ESC直接退出程序（方便开发测试）
        is_locked = false;
#else
        // 系统模式：ESC仅清空当前输入（防止误触退出）
        clear_password();
#endif
        return;
    }

    // 退格键：删除最后一个输入字符（仅当有输入时有效）
    if (IsKeyPressed(KEY_BACKSPACE) && input_pos > 0)
    {
        input_pos--;
        password[input_pos] = '\0'; // 覆盖删除的字符
        return;
    }

    // 回车键（主键盘/小键盘）：提交密码进行认证
    if (IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER))
    {
        if (verify_password())
        {
            is_locked = false; // 认证成功，标记为解锁状态
        }
        else
        {
            clear_password(); // 认证失败，清空输入（防止再次尝试时残留）
        }
        return;
    }

    // 可打印字符捕获（仅允许ASCII 32-126，避免控制字符注入）
    int key = GetCharPressed();
    while (key > 0)
    {
        if (key >= 32 && key <= 126 && input_pos < MAX_PASSWORD_LEN - 1)
        {
            password[input_pos++] = (char)key; // 存储输入字符
#if ENABLE_DEBUG_LOG
            // 调试模式下打印输入字符（方便开发调试）
            fprintf(stderr, "Input: %c (Current Length: %d)\n", (char)key, input_pos);
#endif
        }
        key = GetCharPressed(); // 处理连续输入的字符
    }
}

// ================================================================================
// UI渲染函数（绘制锁屏界面，保证用户体验与安全性）
// 特点：高对比度、无冗余信息、失败提示明确
// ================================================================================
static void draw_ui()
{
    BeginDrawing();                    // Raylib渲染开始（必须在绘制前调用）
    ClearBackground(COLOR_BACKGROUND); // 清空背景（黑色防窥）

    // 获取屏幕尺寸（用于居中布局，适配不同分辨率）
    int screen_w = GetScreenWidth();
    int screen_h = GetScreenHeight();
    Vector2 center = {screen_w / 2.0f, screen_h / 2.0f};

    // 1. 绘制主标题（"System Screen Locked"）
    const char *title = "System Screen Locked";
    Vector2 title_size = MeasureTextEx(GetFontDefault(), title, FONT_SIZE_MAIN, 1);
    DrawText(title, center.x - title_size.x / 2, center.y - 100, FONT_SIZE_MAIN, COLOR_TEXT);

    // 2. 绘制密码提示（"Enter System Password:"）
    const char *prompt = "Enter System Password:";
    Vector2 prompt_size = MeasureTextEx(GetFontDefault(), prompt, FONT_SIZE_SUB, 1);
    DrawText(prompt, center.x - prompt_size.x / 2, center.y - 40, FONT_SIZE_SUB, COLOR_TEXT);

    // 3. 绘制密码输入指示器（用*隐藏真实密码，最多显示80个*）
    char pass_indicator[MAX_PASSWORD_LEN + 1] = {0};
    memset(pass_indicator, '*', input_pos > 80 ? 80 : input_pos); // 限制显示长度防泄露
    Vector2 indicator_size = MeasureTextEx(GetFontDefault(), pass_indicator, FONT_SIZE_INDICATOR, 1);
    DrawText(pass_indicator, center.x - indicator_size.x / 2, center.y + 20, FONT_SIZE_INDICATOR, COLOR_SUCCESS);

    // 4. 绘制认证失败提示（超过次数时显示临时锁定）
    if (failed_attempts > 0)
    {
        char fail_text[64];
        // 格式化失败信息（显示当前次数/最大次数）
        snprintf(fail_text, sizeof(fail_text), "Failed: %d/%d (Too many = temporary block)", failed_attempts, MAX_FAILED_ATTEMPTS);
        Vector2 fail_size = MeasureTextEx(GetFontDefault(), fail_text, FONT_SIZE_SUB - 2, 1);
        DrawText(fail_text, center.x - fail_size.x / 2, center.y + 60, FONT_SIZE_SUB - 2, COLOR_ERROR);

        // 超过最大失败次数：临时锁定输入（防暴力破解）
        if (failed_attempts >= MAX_FAILED_ATTEMPTS)
        {
            const char *block_text = "Temporarily Blocked - Restart to Try Again";
            Vector2 block_size = MeasureTextEx(GetFontDefault(), block_text, FONT_SIZE_SUB - 2, 1);
            DrawText(block_text, center.x - block_size.x / 2, center.y + 100, FONT_SIZE_SUB - 2, COLOR_ERROR);
            EndDrawing(); // 提前结束渲染，跳过其他绘制
            return;
        }
    }

    // 5. 绘制帮助文本（F1切换显示/隐藏）- 修复数组语法错误
    if (show_help)
    {
        // 修复：数组元素用逗号分隔，ESC行为文本单独处理
        const char *esc_behavior = ALLOW_ESC_QUIT ? "Quit (Debug)" : "Clear Input (System)";
        char help_line1[128];
        snprintf(help_line1, sizeof(help_line1), "F1: Toggle Help | ESC Behavior: %s", esc_behavior);

        const char *help_lines[] = {
            help_line1,
            "Enter: Submit Password | Backspace: Delete Last Character"};

        int help_y = screen_h - 80; // 帮助文本放在屏幕底部
        for (int i = 0; i < 2; i++)
        {
            Vector2 help_size = MeasureTextEx(GetFontDefault(), help_lines[i], FONT_SIZE_SUB - 4, 1);
            DrawText(help_lines[i], center.x - help_size.x / 2, help_y + (i * 30), FONT_SIZE_SUB - 4, COLOR_TEXT);
        }
    }
    else
    {
        // 隐藏帮助时显示提示（"Press F1 for Help"）
        const char *help_hint = "Press F1 for Help";
        Vector2 hint_size = MeasureTextEx(GetFontDefault(), help_hint, FONT_SIZE_SUB - 4, 1);
        DrawText(help_hint, screen_w - hint_size.x - 20, screen_h - 40, FONT_SIZE_SUB - 4, COLOR_TEXT);
    }

    EndDrawing(); // Raylib渲染结束（必须在绘制后调用）
}

// ================================================================================
// 系统安全检查函数（确保锁屏在合法环境下运行）
// 返回值：true=环境合法，false=环境异常（终止程序）
// ================================================================================
static bool system_safety_check()
{
    // 可选：限制root用户运行（适合桌面环境下的系统级锁屏，按需启用）
    /*
    if (getuid() != 0) {
        fprintf(stderr, "Error: System locker requires root privilege (run with sudo)\n");
        return false;
    }
    */

    // 检查Raylib窗口初始化状态（确保能正常显示锁屏界面）
    if (IsWindowReady())
        return true;
    fprintf(stderr, "Error: Failed to initialize display (check X11/Wayland service)\n");
    return false;
}

// ================================================================================
// 主函数（程序入口，控制整体流程）
// 流程：参数解析 → 配置验证 → 初始化 → 安全检查 → 主循环 → 资源清理
// ================================================================================
int main(int argc, char *argv[])
{
    // 1. 首先执行配置验证（编译期静态断言，确保宏定义合法）
    validate_config_macros();

    // 2. 解析命令行参数（仅支持-h查看帮助，调试模式通过编译宏控制）
    for (int i = 1; i < argc; i++)
    {
        if (strcmp(argv[i], "-h") == 0)
        {
            printf("System Screen Locker (Version: 1.0)\n");
            printf("Usage: %s [OPTIONS]\n", argv[0]);
            printf("  -h    Show this help message\n");
            printf("Note: Debug mode is enabled via -DDEBUG_MODE during compilation\n");
            return 0;
        }
#if ENABLE_DEBUG_LOG
        else if (strcmp(argv[i], "-d") == 0)
        {
            printf("Warning: Debug mode is already enabled via compile flag\n");
        }
#endif
    }

    // 3. Raylib初始化（全屏窗口，无标题栏，防止被窗口管理器关闭）
    InitWindow(0, 0, WINDOW_TITLE); // 0,0表示自动适配屏幕分辨率
    ToggleFullscreen();             // 切换全屏模式（修复参数问题，无需传参）
    SetTargetFPS(60);               // 限制帧率为60（平衡性能与功耗）
    HideCursor();                   // 隐藏鼠标光标（防止用户点击其他窗口）
    DisableCursor();                // 禁用鼠标输入（额外安全层，防止光标操作）

    // 4. 系统安全检查（失败则退出程序）
    if (!system_safety_check())
    {
        CloseWindow(); // 清理窗口资源
        return 1;      // 返回非0值表示异常退出
    }

    // 5. Linux内存锁定（防止密码缓冲区被交换到磁盘，减少泄露风险）
#ifdef __linux__
    if (mlock(password, sizeof(password)) != 0)
    {
        fprintf(stderr, "Warning: Password memory not locked (run 'ulimit -l unlimited' as root)\n");
    }
#endif

    // 6. 主循环（仅在解锁成功后退出，系统模式下无其他退出途径）
    while (is_locked)
    {
        handle_input(); // 处理键盘输入
        draw_ui();      // 渲染锁屏界面
        // 刻意不检查WindowShouldClose()，防止窗口管理器强制关闭
    }

    // 7. 程序退出前的安全清理（防止敏感数据残留）
#ifdef __linux__
    munlock(password, sizeof(password)); // 解锁内存（释放系统资源）
#endif
    clear_password(); // 清空密码缓冲区（安全合规）
    EnableCursor();   // 启用鼠标（恢复系统正常状态）
    ShowCursor();     // 显示鼠标光标
    CloseWindow();    // 关闭Raylib窗口（释放图形资源）

#if ENABLE_DEBUG_LOG
    printf("System Unlocked Successfully\n"); // 调试模式打印退出日志
#endif
    return 0; // 正常退出
}
